package jd.monitor.agent;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.JarFile;

import org.apache.commons.io.FileUtils;

import jd.monitor.attach.config.BeanContext;
import jd.monitor.attach.config.BeanRoot;
import jd.monitor.attach.util.XmlSerializableUtil;

/**
 * 
 * @author wangyankai
 *
 */
public class AgentAttach {

	@SuppressWarnings("rawtypes")
	public static void agentmain(String agentArgs, Instrumentation inst) {
		
		System.out.println("AgentAttach classLoad is " +AgentAttach.class.getClassLoader().getClass().getName());
		classLoaderAddUrl(inst); 
		BeanRoot beanRoot = null;
		try {
			beanRoot = XmlSerializableUtil.deSerializeXML(BeanRoot.class, FileUtils.readFileToString(new File(agentArgs)), true);
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		if(beanRoot != null){
			BeanContext.getContext().put(BeanContext.BEANROOT, beanRoot) ;
			HashSet<String> beanNames = beanRoot.getBeanNames() ;
			Class[] classes = inst.getAllLoadedClasses() ;
			System.out.println("beanNames = "+beanNames +" classes size "+classes.length);
			for (Class class1 : classes) {
				if(beanNames.contains(class1.getName())){
					System.out.println("className = "+class1.getName() +" classLoad is "+class1.getClassLoader().getClass().getName());
					MonitorTransformer mm = new MonitorTransformer(class1.getClassLoader()) ;
					inst.addTransformer(mm, true);
					try {
						inst.retransformClasses(class1);
					} catch (UnmodifiableClassException e) {
						e.printStackTrace();
					}finally {
						inst.removeTransformer(mm) ;
					}
				}
			}
		}
	}

	/**
	 * 添加依赖jar到系统类路径
	 * @param inst 
	 */
	private static void classLoaderAddUrl(Instrumentation inst) {
		try {
			
//			URLClassLoader classloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
//			Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
//			add.setAccessible(true);
			String pathForJar = AgentAttach.class.getProtectionDomain().getCodeSource().getLocation().getFile();
			if(System.getProperty("os.name").toLowerCase().contains("windows")){
				pathForJar = pathForJar.substring(1);
			}
			JarFile currentJar = new JarFile(pathForJar);
			pathForJar = pathForJar.substring(0, pathForJar.lastIndexOf("/")+1);
			Attributes manifestAttr = currentJar.getManifest().getMainAttributes();
			String manifestJarName = manifestAttr.getValue("JarName-Depend");
			final List<String> refJar = Arrays.asList(manifestJarName.split("\\s"));
			// 文件名过滤
			FilenameFilter nameFilter = new FilenameFilter() {
				
				@Override
				public boolean accept(File dir, String name) {
					for (String refName : refJar) {
						if(name.startsWith(refName)){
							return true ;
						}
					}
					return false;
				}
			};
			File allJarDir = new File(pathForJar) ;
			String[] jarName = allJarDir.list(nameFilter) ;
			for (String name : jarName) {
//				add.invoke(classloader, new Object[] { new File(pathForJar+name).toURI().toURL() }) ;
				inst.appendToSystemClassLoaderSearch(new JarFile(pathForJar+name));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
